import { init } from 'snabbdom/build/package/init.js'
import { classModule } from 'snabbdom/build/package/modules/class.js'
import { propsModule } from 'snabbdom/build/package/modules/props.js'
import { styleModule } from 'snabbdom/build/package/modules/style.js'
import { eventListenersModule } from 'snabbdom/build/package/modules/eventlisteners.js'
import { h } from 'snabbdom/build/package/h.js'
// patch 是snabbdom得核心函数 
// 参数：数组，模块
// 返回值： patch函数， 作用是对比两个虚拟DOM -> snabbdom 中得VNode 的差异更新到真实DOM
var patch = init([classModule, propsModule, styleModule, eventListenersModule])

var vnode

var nextKey = 11
var margin = 8
var sortBy = 'rank'
var totalHeight = 0
var originalData = [
  { rank: 1, title: 'The Shawshank Redemption', desc: 'Two imprisoned men bond over a number of years, finding solace and eventual redemption through acts of common decency.', elmHeight: 0 },
  { rank: 2, title: 'The Godfather', desc: 'The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son.', elmHeight: 0 },
  { rank: 3, title: 'The Godfather: Part II', desc: 'The early life and career of Vito Corleone in 1920s New York is portrayed while his son, Michael, expands and tightens his grip on his crime syndicate stretching from Lake Tahoe, Nevada to pre-revolution 1958 Cuba.', elmHeight: 0 },
  { rank: 4, title: 'The Dark Knight', desc: 'When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.', elmHeight: 0 },
  { rank: 5, title: 'Pulp Fiction', desc: 'The lives of two mob hit men, a boxer, a gangster\'s wife, and a pair of diner bandits intertwine in four tales of violence and redemption.', elmHeight: 0 },
  { rank: 6, title: 'Schindler\'s List', desc: 'In Poland during World War II, Oskar Schindler gradually becomes concerned for his Jewish workforce after witnessing their persecution by the Nazis.', elmHeight: 0 },
  { rank: 7, title: '12 Angry Men', desc: 'A dissenting juror in a murder trial slowly manages to convince the others that the case is not as obviously clear as it seemed in court.', elmHeight: 0 },
  { rank: 8, title: 'The Good, the Bad and the Ugly', desc: 'A bounty hunting scam joins two men in an uneasy alliance against a third in a race to find a fortune in gold buried in a remote cemetery.', elmHeight: 0 },
  { rank: 9, title: 'The Lord of the Rings: The Return of the King', desc: 'Gandalf and Aragorn lead the World of Men against Sauron\'s army to draw his gaze from Frodo and Sam as they approach Mount Doom with the One Ring.', elmHeight: 0 },
  { rank: 10, title: 'Fight Club', desc: 'An insomniac office worker looking for a way to change his life crosses paths with a devil-may-care soap maker and they form an underground fight club that evolves into something much, much more...', elmHeight: 0 },
]

var data = [
  originalData[0],
  originalData[1],
  originalData[2],
  originalData[3],
  originalData[4],
  originalData[5],
  originalData[6],
  originalData[7],
  originalData[8],
  originalData[9],
]

// 根据传递的参数来对内容进行排序
function changeSort (prop) {
  sortBy = prop
  // 判断属性大小来进行排序
  data.sort((a, b) => {
    if (a[prop] > b[prop]) {
      return 1
    }
    if (a[prop] < b[prop]) {
      return -1
    }
    return 0
  })
  // 更新真实DOM并更改列表属性变量
  render()
}

// 添加列表项
function add () {
  // 随机获取数组中任一项
  var n = originalData[Math.floor(Math.random() * 10)]
  // 将其添加至列表内容中
  data = [{ rank: nextKey++, title: n.title, desc: n.desc, elmHeight: 0 }].concat(data)
  // 更新真实DOM并更改列表属性变量
  // 第一次添加的数据还未添加到新增div中
  render()
  // 第二次将添加的数据渲染出来
  render()
}

// 移除列表项
function remove (movie) {
  data = data.filter((m) => {
    // 返回满足条件的列表项  组成新的数组
    return m !== movie
  })
  // 更新真实DOM并更改列表属性变量
  render()
}

// 列表数据渲染
function movieView (movie) {
  // 创建列表项div 并设置相关属性
  return h('div.row', {
    key: movie.rank,
    style: {
      opacity: '0',
      transform: 'translate(-200px)',
      delayed: { transform: `translateY(${movie.offset}px)`, opacity: '1' },
      remove: { opacity: '0', transform: `translateY(${movie.offset}px) translateX(200px)` }
    },
    hook: { insert: (vnode) => { movie.elmHeight = vnode.elm.offsetHeight } },
  }, [
    // 序号
    h('div', { style: { fontWeight: 'bold' } }, movie.rank),
    // 标题
    h('div', movie.title),
    // 描述
    h('div', movie.desc),
    // div实现的删除按钮 
    h('div.btn.rm-btn', { on: { click: remove.bind(null, movie) } }, 'x'),
  ])
}

function render () {
  // 更新data数据中的内容 并设置列表项的box属性
  data = data.reduce((acc, m) => {
    var last = acc[acc.length - 1]
    m.offset = last ? last.offset + last.elmHeight + margin : margin
    return acc.concat(m)
  }, [])
  // 更改列表的总体高度
  totalHeight = data.length === 0
    ? 0
    : data[data.length - 1].offset + data[data.length - 1].elmHeight
  // 对比虚拟DOM差异，将变化更新到真实DOM中 
  vnode = patch(vnode, view(data))
}

function view (data) {
  // 第一个参数： 标签+选择器
  // 第二个参数： 如果是字符串的话就是标签中的内容 / 数组是子元素 / 也可以是数据对象，则其他内容顺延
  return h('div', [
    h('h1', 'Top 10 movies'),
    h('div', [
      // a标签的“添加元素”按钮  绑定事件   标签内容
      h('a.btn.add', { on: { click: add } }, 'Add'),
      'Sort by: ',
      // a标签的三个改变列表排序的按钮  类型动态添加  绑定排序事件  标签内容
      h('span.btn-group', [
        h('a.btn.rank', { class: { active: sortBy === 'rank' }, on: { click: changeSort.bind(null, 'rank') } }, 'Rank'),
        h('a.btn.title', { class: { active: sortBy === 'title' }, on: { click: changeSort.bind(null, 'title') } }, 'Title'),
        h('a.btn.desc', { class: { active: sortBy === 'desc' }, on: { click: changeSort.bind(null, 'desc') } }, 'Description'),
      ]),
    ]),
    // 列表内容显示  列表属性  列表内容遍历加载
    h('div.list', { style: { height: totalHeight + 'px' } }, data.map(movieView)),
  ])
}

window.addEventListener('DOMContentLoaded', () => {
  var container = document.getElementById('container')
  // 将真实DOM转换为虚拟DOM，对比两个虚拟DOM的差异，将差异的内容更新到真实DOM
  vnode = patch(container, view(data))
  // 更新真实DOM并更改列表属性变量
  render()
})